using System;
using System.Collections.Generic;
using System.Linq;
using Charisma.MongoDb;
using Charisma.Tests.Models.BlogApp;
using NUnit.Framework;
using System.Reflection;
using FluentAssertions;

namespace Charisma.Tests
{
    [TestFixture]
    public class FluentConfigurationTests
    {
        private static DbModelBuilder GetDbModelBuilder()
        {
            return new DbModelBuilder(typeof(BlogAppContext));
        }

        [Test]
        public void RegisterEntityTest()
        {
            var dbModelBuilder = GetDbModelBuilder();
            var ec = dbModelBuilder.Entity<Post>();

            ec.Should().NotBeNull();
            dbModelBuilder.Configurations.GetEntities().Should().HaveCount(1);
        }

        [Test]
        public void RegisterSameEntityTest()
        {
            var dbModelBuilder = GetDbModelBuilder();
            dbModelBuilder.Entity<Post>();
            Action action = () => dbModelBuilder.Entity<Post>();
            action.ShouldThrow<InvalidOperationException>();

            var ec = dbModelBuilder.Configurations.GetEntities().Where(c => c.GetType() == typeof(Post));
            ec.Should().NotBeNull();
            dbModelBuilder.Configurations.GetEntities().Should().HaveCount(1);
        }

        [Test]
        public void RegisterIdPropertyTest()
        {
//            var dbModelBuilder = GetDbModelBuilder();
//
//            dbModelBuilder.Repository(c => c.Blogs).HasIdentity(b => b.Id);
//            var ec = dbModelBuilder.Configurations.GetEntities().Find(typeof(Blog));
//            Assert.IsNotNull(ec.GetMembers().Values.Where(p => p.IsKey).FirstOrDefault());
        }

        [Test]
        public void RegisterSameIdPropertyTest()
        {
//            var dbModelBuilder = GetDbModelBuilder();
//
//            dbModelBuilder.Repository(c => c.Blogs).HasIdentity(b => b.Id);
//            dbModelBuilder.Repository(c => c.Blogs).HasIdentity(b => b.Id);
//
//            var ec = dbModelBuilder.Configurations.GetEntities().Find(typeof(Blog));
//            Assert.AreEqual(1, ec.GetMembers().Values.Where(p => p.IsKey).Count());
        }

        [Test]
        public void RegisterAnotherIdPropertyTest()
        {
//            var dbModelBuilder = GetDbModelBuilder();
//
//            dbModelBuilder.Repository(c => c.Blogs).HasIdentity(b => b.Id);
//            dbModelBuilder.Repository(c => c.Blogs).HasIdentity(b => b.Title);
//
//            var ec = dbModelBuilder.Configurations.GetEntities().Find(typeof(Blog));
//            Assert.AreEqual(1, ec.GetMembers().Values.Where(p => p.IsKey).Count());
//            Assert.AreEqual("Title", ec.GetMembers().Values.Where(p => p.IsKey).First().Field.Name);
        }

        [Test]
        public void RegisterIgnorePropertyTest()
        {
            var dbModelBuilder = GetDbModelBuilder();
            dbModelBuilder.Entity<Post>().Ignore(p => p.Comments);

            var ec = dbModelBuilder.Configurations.GetEntities().Find(typeof(Post));
            ec.GetMembers().Values.Where(p => p.GetIsIgnored()).Should().HaveCount(1);
        }

        [Test]
        public void RegisterSameIgnorePropertyTest()
        {
            var dbModelBuilder = GetDbModelBuilder();

            dbModelBuilder.Entity<Post>().Ignore(p => p.Comments);

            Action action = () => dbModelBuilder.Entity<Post>().Ignore(p => p.Comments);
            action.ShouldThrow<InvalidOperationException>();

            var ec = dbModelBuilder.Configurations.GetEntities().Find(typeof(Post));
            ec.GetMembers().Values.Where(p => p.GetIsIgnored()).Should().HaveCount(1);
        }

        [Test]
        public void RegisterRepositoryTest()
        {
            var dbModelBuilder = GetDbModelBuilder();

            dbModelBuilder.Repository<BlogAppContext, Blog>(context => context.Blogs);

            dbModelBuilder.Configurations.GetRepositories().Should().HaveCount(1);
            var rc = dbModelBuilder.Configurations.GetRepositories().Find("Blogs");
            rc.Should().NotBeNull();
            rc.GetMember().Should().NotBeNull();
            rc.GetMemberName().Should().NotBeEmpty();
        }

        [Test]
        public void RegisterSameRepositoryTest()
        {
            var dbModelBuilder = GetDbModelBuilder();

            dbModelBuilder.Repository<BlogAppContext, Blog>(context => context.Blogs);

            Action action = () => dbModelBuilder.Repository<BlogAppContext, Blog>(context => context.Blogs);
            action.ShouldThrow<InvalidOperationException>();

            dbModelBuilder.Configurations.GetRepositories().Should().HaveCount(1);
        }

        [Test]
        public void RegisterRepositoryNameTest()
        {
            var dbModelBuilder = GetDbModelBuilder();

            dbModelBuilder.Repository<BlogAppContext, Blog>(context => context.Blogs).HasName("BlogCollection");

            var rc = dbModelBuilder.Configurations.GetRepositories().Find("Blogs");
            rc.Should().NotBeNull();
            rc.GetMember().Should().NotBeNull();
            rc.GetMemberName().Should().NotBeEmpty();
            rc.GetName().Should().Be("BlogCollection");
        }

        [Test]
        public void RegisterDuplicateRepositoryNameTest1()
        {
            var dbModelBuilder = GetDbModelBuilder();

            dbModelBuilder.Repository<BlogAppContext, Blog>(context => context.Blogs).HasName("MyCollection");
            dbModelBuilder.Repository<BlogAppContext, Person>(context => context.Persons).HasName("MyCollection");

            dbModelBuilder.Configurations.GetRepositories().Should().HaveCount(2);
        }

        [Test]
        public void RegisterDuplicateRepositoryNameTest2()
        {
            var dbModelBuilder = GetDbModelBuilder();

            dbModelBuilder.Repository<BlogAppContext, Blog>(context => context.Blogs);
            dbModelBuilder.Repository<BlogAppContext, Person>(context => context.Persons).HasName("Blogs");

            dbModelBuilder.Configurations.GetRepositories().Should().HaveCount(2);
        }

        [Test]
        public void RegisterDuplicateRepositoryNameTest3()
        {
            var dbModelBuilder = GetDbModelBuilder();

            dbModelBuilder.Repository<BlogAppContext, Blog>(context => context.Blogs).HasName("Persons");
            dbModelBuilder.Repository<BlogAppContext, Person>(context => context.Persons);

            dbModelBuilder.Configurations.GetRepositories().Should().HaveCount(2);
        }
    }
}